function An = slvecnorm(A, p, d)
%SLVECNORM Compute the Lp-norms of vectors
%
% [ Syntax ]
%   - An = slvecnorm(A)
%   - An = slvecnorm(A, p)
%   - An = slvecnorm(A, [], d)
%   - An = slvecnorm(A, p, d)
%
% [ Arguments ]
%   - A:        the input array
%   - p:        the order of the norm (default = 2)
%   - d:        the along which the norm values of vectors are computed
%   - An:       the resultant array of norm values.
%
% [ Description ]
%   - An = slvecnorm(A) computes the L2 norm of column vectors of A. 
%
%     If A is an array of size d1 x d2 x ... dn, then An would be of size 
%     1 x d2 x ... dn. Each value of An is the L2 norm of corresponding
%     column vector.
%
%   - An = slvecnorm(A, p) computes the Lp norm of column vectors of A. 
%
%   - An = slvecnorm(A, [], d) computes the L2 norm of vectors along the 
%     dimensions specified by d. 
%
%     If A is a d1 x d2 x ... dn array, and d = 2, then An would be an 
%     array of size d1 x 1 x d3 x ... x dn. Each value of An is L2-norm
%     of the corresponding row vector.
%
%   - An = slvecnorm(A, p, d) computes the Lp norm of vectors along the 
%     dimensions specified by d.
%
% [ Remarks ]
%   # Lp norm is the pth order-root of the sum of p-th power of all values
%     in a vector. 
%   # p can be inf or -inf. If p = inf, then the Lp norm is simply the
%     maximum magnitude value; while if p = -inf, then the Lp norm is the 
%     minimum magnitude value.
%   # If p is zero, then all norm values are inf.     
%
% [ History ]
%   - Created by Dahua Lin on Nov 19th, 2005
%   - Modified by Dahua Lin, on Jul 2nd, 2007
%       - Change the name to slvecnorm, which focuses on computing vector
%         norms. 
%       - Rewrite the core. The new core is based on MATLAB builtin
%         functions.
%       - Allow L0-norm (p = 0).
%       - Reduce the unnecessary absolute-value computation
%

%% parse and verify input arguments
if nargin < 2 || isempty(p)
    p = 2;
end
if nargin < 3 || isempty(d)
    d = 1;
end
if ~isnumeric(p) || ~isscalar(p) 
    error('sltoolbox:slvecnorm:illegalarg', 'p should be a numeric scalar');
end


%% compute

if d <= ndims(A)
    if p == 2
        An = sqrt(sum(A .* A, d));
    elseif p == 1
        An = sum(A, d);
    elseif p == 0
        newsize = size(A);
        newsize(d) = 1;
        An = inf(newsize);
    elseif p == inf;
        An = max(A, [], d);
    elseif p == -inf;
        An = min(A, [], d);
    elseif p > 0 && mod(p, 2) == 0
        An = sum(A .^ p, d) .^ (1/p);
    else
        An = sum(abs(A) .^ p, d) .^ (1/p);
    end
else
    An = A;
end
                
